package com.jltx.zeus.viewmodel

import android.app.Activity
import android.content.Context
import android.content.Intent
import androidx.annotation.IntDef
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.ViewModelStoreOwner
import com.jltx.zeus.viewmodel.ProduceResultStatus.Companion.STATUS_FAIL
import com.jltx.zeus.viewmodel.ProduceResultStatus.Companion.STATUS_LOADING
import com.jltx.zeus.viewmodel.ProduceResultStatus.Companion.STATUS_SUCCESS
import java.lang.annotation.Retention
import java.lang.annotation.RetentionPolicy

/**
 * @author jltxseo
 *         Created by junlintianxia on 2020/05/10.
 */
open class BaseActionEvent

class ShowLoadingEvent(val message: String) : BaseActionEvent()

object DismissLoadingEvent : BaseActionEvent()

object FinishViewEvent : BaseActionEvent()


@Retention(RetentionPolicy.SOURCE)
@IntDef(STATUS_LOADING, STATUS_SUCCESS, STATUS_FAIL)
annotation class ProduceResultStatus {
    companion object {
        const val STATUS_LOADING = 0
        const val STATUS_SUCCESS = 1
        const val STATUS_FAIL = 2
    }
}

class ProduceResult<T> {
    var status = 0
    var progress: Float = 0f
    var error: Throwable? = null
    var data: T? = null
}

/**
 * 用于定义 View均需要实现的一些 UI 层行为
 */
interface ActionEvent : CoroutineEvent {

    fun showLoading(msg: String)

    fun dismissLoading()

    fun finishView()

}

interface ActionEventObserver : ActionEvent {

    val lContext: Context?

    val lLifecycleOwner: LifecycleOwner

    fun <T : BaseViewModel> getViewModel(
        clazz: Class<T>,
        initializer: (T.(lifecycleOwner: LifecycleOwner) -> Unit)? = null
    ): Lazy<T> {
        return lazy {
            getViewModelFast(clazz, initializer)
        }
    }

    private fun <T : BaseViewModel> getViewModelFast(
        clazz: Class<T>,
        initializer: (T.(lifecycleOwner: LifecycleOwner) -> Unit)? = null
    ): T {
        return when (val localValue = lLifecycleOwner) {
            is ViewModelStoreOwner -> {
                ViewModelProvider(localValue).get(clazz)
            }
            else -> {
                clazz.newInstance()
            }
        }.apply {
            observerActionEvent()
            initializer?.invoke(this, lLifecycleOwner)
        }
    }

    fun <T : BaseAndroidViewModel> getAndroidViewModel(
        clazz: Class<T>,
        initializer: (T.(lifecycleOwner: LifecycleOwner) -> Unit)? = null
    ): Lazy<T> {
        return lazy {
            getAndroidViewModelFast(clazz, initializer)
        }
    }

    private fun <T : BaseAndroidViewModel> getAndroidViewModelFast(
        clazz: Class<T>,
        initializer: (T.(lifecycleOwner: LifecycleOwner) -> Unit)? = null
    ): T {
        return when (val localValue = lLifecycleOwner) {
            is ViewModelStoreOwner -> {
                ViewModelProvider(localValue).get(clazz)
            }
            else -> {
                clazz.newInstance()
            }
        }.apply {
            observerActionEvent()
            initializer?.invoke(this, lLifecycleOwner)
        }
    }

    fun BaseAndroidViewModel.observerActionEvent() {
        vmActionEvent.observe(lLifecycleOwner, Observer {
            generateActionEvent(it)
        })
    }

    fun BaseViewModel.observerActionEvent() {
        vmActionEvent.observe(lLifecycleOwner, Observer {
            generateActionEvent(it)
        })
    }

    fun generateActionEvent(baseActionEvent: BaseActionEvent) {
        when (baseActionEvent) {
            is ShowLoadingEvent -> {
                this@ActionEventObserver.showLoading(baseActionEvent.message)
            }
            DismissLoadingEvent -> {
                this@ActionEventObserver.dismissLoading()
            }
            FinishViewEvent -> {
                this@ActionEventObserver.finishView()
            }
        }
    }

    fun <T : Activity> startActivity(clazz: Class<T>) {
        lContext?.apply {
            startActivity(Intent(this, clazz))
        }
    }

}